<?PHP
	/************************************************************************
	*       This file, in addition to all other parts of X7 Chat are        *
	*                   Copyright 2003-2007 by Tim Chamness.                *
	* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
	* Version:          X7 Chat 3.0.0-A2                                    *
	* Release Date:     October 20, 2007                                    *
	* Author:           Tim Chamness                                        *
	* Copyright:        2003-2007 by Tim Chamness                           *
	* Website:          http://www.x7chat.com/                              *
	* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
	* X7 Chat 3 is free software; you can redistribute it and/or modify     *
	* it under the terms of the GNU General Public License as published by  *
	* the Free Software Foundation; either version 3 of the License, or     *
	* (at your option) any later version.                                   *
	*                                                                       *
	* X7 Chat 3 is distributed in the hope that it will be useful, but      *
	* WITHOUT ANY WARRANTY; without even the implied warranty of            *
	* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
	* General Public License for more details.                              *
	*                                                                       *
	* You should have received a copy of the GNU General Public License     *
	* along with this program.  If not, see <http://www.gnu.org/licenses/>. *
	*                                                                       *
	* Additional Terms, compatible with Section 7 of the GNU GPL v3,        *
	* apply to X7 Chat 3 and all X7 Chat 3 files, including this one.       *
	* You should have received a copy of these Additional Terms in the      *
	* file docs/COPYING.ADDITIONAL_TERMS.  If you did not receive a copy    *
	* please visit <http://www.x7chat.com/COPYING.ADDITIONAL_TERMS/>.       *
	************************************************************************/

	/**
	 * Controls the template engine.  To get the value of a particular template
	 * of the current theme one should call template_file::template_name();.  
	 * Templates can get data from the script through template variables.  Template
	 * variables are set directly by doing $lib_output->varname = 'varvalue'; or
	 * can be set by reference using lib_output::assign_by_ref().
	 */
	class lib_output {
		private $theme;
		
		private $theme_dir = './themes';
		
		/**
		 * Setup a new theme controller using a specified theme
		 *
		 * @param string $theme The name of the theme to use.
		 */
		public function __construct($theme){
			$this->set_theme($theme);
		}
		
		/**
		 * Change the theme that this output library is using.
		 *
		 * @param string $theme The name of the theme to use.
		 */
		public function set_theme($theme){
			$this->theme = $theme;
			
			// Make sure this theme exists.
			if(!is_dir($this->theme_dir.'/'.$theme))
					trigger_error('Unable to load theme `'.$theme.'`',E_USER_ERROR);
		}
		
		/**
		 * Get HTML for a particular template in this theme.
		 *
		 * @param string $class The name of the template file to get.
		 */
		public function load_template_file($class){
			if(!is_file($this->theme_dir.'/'.$this->theme.'/templates/'.$class.'.php'))
				trigger_error('Missing template file '.$class.' from theme '.$this->theme,E_USER_ERROR);
			
			include($this->theme_dir.'/'.$this->theme.'/templates/'.$class.'.php');
		}
		
		/**
		 * Assign a template variable by reference.  Normal
		 * variable assignments are simply done by doing
		 * $this->var_name = 'value';, however that doesn't
		 * work for references.
		 *
		 * @param string $var The name of the template variable to set
		 * @param mixed $value The object or array to point that variable to
		 */
		public function assign_by_ref($var,&$value){
			$this->$var = null;
			$this->$var =& $value;
		}
		
		public function __get($var){
			trigger_error('Tried to access undefined template variable '.$var,E_USER_ERROR);
		}
	}

	/**
	 * Controls a group of language files known as a language pack.
	 * After creating an instance of this class, you can access the
	 * translation in a given language file by accessing 
	 * $instance->lang_filename->lang_varname;
	 */
	class language_controller {
		private $language_files;
		private $language;
		
		private $lang_dir = './languages';
		
		/**
		 * Create a new language controller
		 *
		 * @param string $language The name of the language to use.
		 */
		public function __construct($language){
			$this->language_files = array();
			$this->language = $language;
			
			if(!is_dir($this->lang_dir.'/'.$language))
					trigger_error('Unable to load language '.$language,E_USER_ERROR);
		}
		
		public function __get($lf){
			$this->$lf = new language_file($this->lang_dir.'/'.$this->language.'/'.$lf.'.php');
			return $this->$lf;
		}
		
		public function format($string){
			$args = func_get_args();
			array_shift($args);
			
			foreach($args as $argv){
				if(is_array($argv))
					$string = str_replace('%'.$argv[0].'%',$argv[1],$string);
			}
			
			return $string;
		}
	}
	
	/**
	 * A class containing the language variables of a single language file
	 * in a language pack.  Instance of this should only be created by the
	 * language controller.
	 */
	class language_file {
		private $file;
		
		public function __construct($lf){
			if(is_file($lf))
				require($lf);
			else
				$this->file = $lf;
		}
		
		public function __get($v){
			return $this->file ? 'Undefined Translation `'.$v.'`' : 'Missing Language File `'.$this->file.'`';
		}
	}
	
	//$form->add_field_checkbox($section,$name,$label,$description='');
	//$form->add_field_select($section,$name,$label,$options,$description='',$multi=false);
	//$form->add_field_radio($section,$name,$label,$options,$description='');
	//$form->add_field_file($section,$name,$label,$description='');
	//$form->add_field_hidden($section,$name,$value,$mode=0);
	class x7form {
		private $fields;
		private $sections;
		private $has_errors;
		private $form_message;
		
		public function __construct(){
			$this->fields = array();
			$this->sections = array();
			$this->has_errors = false;
		}
		
		public function add_section($secid,$title='',$desc=''){
			$this->sections[$secid] = array('fields'=>array(),'title'=>$title,'desc'=>$desc,'errors'=>array());
		}
		
		public function form_message($msg){
			$this->form_message = $msg;
		}
		
		public function add_field_hidden($secid,$name,$value,$mode=lib_input::ALLOWALL){
			if(!isset($this->sections[$secid])) $this->add_section($secid);
			$this->sections[$secid]['fields'][$name] = array('type'=>'hidden','default'=>$value,'mode'=>$mode);
			$this->fields[$name] =& $this->sections[$secid]['fields'][$name];
		}
		
		public function add_field_checkbox($secid,$name,$label,$description='',$default=false){
			if(!isset($this->sections[$secid])) $this->add_section($secid);
			$this->sections[$secid]['fields'][$name] = array('type'=>'checkbox','label'=>$label,'desc'=>$description,'default'=>$default,'errors'=>array(),'mode'=>lib_input::BOOLEAN);
			$this->fields[$name] =& $this->sections[$secid]['fields'][$name];
		}
		
		public function add_field_select($secid,$name,$label,$options,$default='',$mode=lib_input::ALLOWALL,$description=''){
			if(!isset($this->sections[$secid])) $this->add_section($secid);
			$this->sections[$secid]['fields'][$name] = array('type'=>'select','label'=>$label,'desc'=>$description,'default'=>$default,'errors'=>array(),'mode'=>$mode,'options'=>$options);
			$this->fields[$name] =& $this->sections[$secid]['fields'][$name];
		}
		
		public function add_field_text($secid,$name,$label,$default='',$mode=lib_input::ALLOWALL,$description=''){
			if(!isset($this->sections[$secid])) $this->add_section($secid);
			$this->sections[$secid]['fields'][$name] = array('type'=>'text','label'=>$label,'desc'=>$description,'default'=>$default,'errors'=>array(),'mode'=>$mode);
			$this->fields[$name] =& $this->sections[$secid]['fields'][$name];
		}
		
		public function add_field_pass($secid,$name,$label,$description=''){
			if(!isset($this->sections[$secid])) $this->add_section($secid);
			$this->sections[$secid]['fields'][$name] = array('type'=>'password','label'=>$label,'desc'=>$description,'default'=>'','errors'=>array());
			$this->fields[$name] =& $this->sections[$secid]['fields'][$name];
		}
		
		public function add_field_error($field,$error,$reset_default=null){
			$this->fields[$field]['errors'][] = $error;
			
			if($reset_default !== null)
				$this->fields[$field]['default'] = $reset_default;
				
			$this->has_errors = true;
		}
		
		public function add_section_error($secid,$error){
			$this->sections[$secid]['errors'][] = $error;
			$this->has_errors = true;
		}
		
		public function get_results(){
			
			$output = array();
			
			foreach($this->fields as $name=>$val){
				switch($val['type']){
					case 'text':
					case 'hidden':
						$output[$name] = lib_input::read($name,null,$val['mode']);
					break;
					case 'password':
						$output[$name] = lib_input::read($name,null,lib_input::ALLOWALL);
					break;
					case 'checkbox':
						$output[$name] = lib_input::read($name,null,lib_input::BOOLEAN);
					break;
					case 'select':
						$output[$name] = lib_input::read($name,null,$this->fields[$name]['options']);
					break;
					default:
						$output[$name] = null;
					break;
				}
				
				if($output[$name] === null && $val['type'] != 'checkbox'){
					return false;
				}elseif($output[$name] !== null)
					$this->fields[$name]['default'] = $output[$name];
			}
			
			return $output;
		}
		
		public function has_errors(){
			return $this->has_errors;
		}
		
		public function get_sections(){
			return $this->sections;
		}
		
		public function get_message(){
			return $this->form_message;
		}
	}
	
	/**
	 * Since the entire purpose of this script is to essentially collect, store and display information
	 * from forms, this class simplifies the handling of forms.
	 */
	class form {
		private $form_fields;
		private $defaults;
		private $errors;
		
		/**
		 * Creates a new form.
		 */
		public function __construct(){
			$this->form_fields = array();
			$this->defaults = array();
			$this->errors = array();
		}
		
		/**
		 * Adds a field to this form
		 *
		 * @param string $fieldtype The type of field to add
		 * @param string $fieldname The name of the field to add
		 * @param string $label The label text for the field
		 * @param string $desc The description of the field
		 * @param array $options The options for the field (for a select box)
		 */
		public function add_field($fieldtype,$fieldname,$label='',$desc='',$options=array()){
			$this->form_fields[] = array($fieldtype,$fieldname,$label,$desc,$options);
		}
		
		/**
		 * Generates the HTML for the field.
		 *
		 * @return The HTML for this field.
		 */
		public function get_fields(){
			$output = '';
			
			foreach($this->form_fields as $form_data){
				
				switch($form_data[0]){
					case 'text':
					case 'password':
					case 'file':
						$form_data[0] = tpl_form::text_password_file($form_data[0],$form_data[1],isset($this->defaults[$form_data[1]]) ? $this->defaults[$form_data[1]] : '');
					break;
					case 'checkbox':
						$form_data[0] = tpl_form::checkbox($form_data[1],isset($this->defaults[$form_data[1]]) ? $this->defaults[$form_data[1]] : '');
					break;
					case 'select':
						$form_data[0] = tpl_form::select($form_data[1],$form_data[4],isset($this->defaults[$form_data[1]]) ? $this->defaults[$form_data[1]] : '');
					break;
				}
				
				$output .= tpl_form::row_wrapper($form_data[0],$form_data[1],$form_data[2],$form_data[3],$form_data[4],isset($this->errors[$form_data[1]]) ? $this->errors[$form_data[1]] : '');
			}
			
			return $output;
		}
		
		/**
		 * Uses the values in the argument as default values for the form.
		 * The array should be in the form array('field name'=>'default_value');
		 *
		 * @param array $array The array containing the default values for form fields.
		 */
		public function add_default_array($array){
			if(is_array($array))
				$this->defaults = array_merge($this->defaults,$array);
		}
		
		/**
		 * Gets the submitted value of a form field and sets the default value
		 * to the submitted value.
		 *
		 * @param string $field The name of the field to get the value of
		 * @param string $modes Specifies the cleaning method that should be used on the input
		 * @return The submitted value of that field.
		 */
		public function get_add_default($field,$modes='f'){
			$this->defaults[$field] = x7in::read($field,$modes);
			return $this->defaults[$field];
		}
		
		/**
		 * Adds a default value for a specific field
		 *
		 * @param string $field The field to add the default value for
		 * @param string $value The default value for that field.
		 * @return The default value
		 */
		public function add_default($field,$value){
			$this->defaults[$field] = $value;
			return $value;
		}
		
		/**
		 * Add an error message to a specific field
		 *
		 * @param string $field The field to add the error message to
		 * @param string $error_message The error message to display next to that field
		 */
		public function add_error($field,$error_message){
			if($field == null)
				$this->formerror = $error_message;
			else
				$this->errors[$field] = $error_message;
		}
		
		/**
		 * Checks to see if any errors have been added to any form fields in this form.
		 *
		 * @return True if errors have been added, false if they have not been.
		 */
		public function has_errors(){
			return !empty($this->errors);
		}
		
	}
	
?>